﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace PickGold.Util.OCR.QRCode.Render
{
	public class SVGRenderer
	{
		private ISizeCalculation _Size;

		private GColor _DarkColor;
		private GColor _LightColor;

		public SVGRenderer(ISizeCalculation isize, GColor darkcolor, GColor lightcolor)
		{
			this._Size = isize;
			this._DarkColor = darkcolor;
			this._LightColor = lightcolor;
		}

		public void WriteToStream(BitMatrix matrix, Stream stream)
		{
			this.WriteToStream(matrix, stream, true);
		}

		public void WriteToStream(BitMatrix matrix, Stream stream, bool includeSize)
		{
			using (var writer = new StreamWriter(stream))
			{
				var sb = new StringBuilder();
				sb.AppendHeader();
				this.AppendSVGQrCode(sb, matrix, includeSize, true);
				writer.Write(sb.ToString());
			}
		}

		public string WriteToString(BitMatrix matrix)
		{
			return this.WriteToString(matrix, true);
		}

		public string WriteToString(BitMatrix matrix, bool includeSize)
		{
			var sb = new StringBuilder();
			this.AppendSVGQrCode(sb, matrix, includeSize, false);
			return sb.ToString();
		}

		private void AppendSVGQrCode(StringBuilder sb, BitMatrix matrix, bool includeSize, bool isStream)
		{
			var dsize = this._Size.GetSize(matrix.Width);
			var pixelwidth = this._Size.GetSize(matrix.Width).CodeSize;
			var quietZone = dsize.QuietZoneModules;
			var width = matrix.Width;
			sb.AppendSVGTag(includeSize ? new MatrixPoint(pixelwidth, pixelwidth) : new MatrixPoint(0, 0),
				new MatrixPoint(2 * quietZone + width, 2 * quietZone + width), _LightColor, _DarkColor);
			if (!isStream)
				sb.Append(@"<!-- Created with Qrcode.Net (http://qrcodenet.codeplex.com/) -->");
			AppendDarkCell(sb, matrix, quietZone, quietZone);
			sb.AppendSVGTagEnd();
		}

		private static void AppendDarkCell(StringBuilder sb, BitMatrix matrix, int offsetX, int offSetY)
		{
			if (matrix == null)
				return;

			var width = matrix.Width;
			var pre = -1;

			for (var y = 0; y < width; y++)
			{
				for (var x = 0; x < width; x++)
				{
					if (matrix[x, y])
					{
						//Set start point if preX == -1
						if (pre == -1)
							pre = x;
						//If this is last module in that row. Draw rectangle
						if (x == width - 1)
						{
							sb.AppendRec(new MatrixPoint(pre + offsetX, y + offSetY), new MatrixPoint(x - pre + 1, 1));
							pre = -1;
						}
					}
					else if (!matrix[x, y] && pre != -1)
					{
						//Here will be first light module after sequence of dark module.
						//Draw previews sequence of dark Module
						sb.AppendRec(new MatrixPoint(pre + offsetX, y + offSetY), new MatrixPoint(x - pre, 1));
						pre = -1;
					}
				}
			}
		}
	}
}
